package com.sang.xmlparser;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.HashMap;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import com.sang.database.CiteseerDb;

public class Xmlparser {
	
//++++++++++++++++++++++++++++++ 变量声明部分 ++++++++++++++++++++++/

	//常量部分
	private static final int NUM_OF_RECORDS = 716800;//总共的记录数
	public static final int NUM_OF_XML_SPLITS = 72;//xml文件的个数(默认数据源由72个小的xml构成)

	private HashMap<String, Integer> authors = new HashMap<String, Integer>();

//	 private static String pathPrefix = "../resource/";

	private int authorId = NUM_OF_RECORDS + 1;//Author的起始id
	private CiteseerDb cdb;
	private XMLStreamReader reader;
	private String log = "log.txt";
	private FileWriter logfw = null;
	private static String exePath = getProjectPath();

	public static CiteseerDb getDb() {
		return CiteseerDb.newInstance(new String[] { "vertex", "edge" });
	}
	
	//得到jar文件或.MainClass文件的目录
	public static String getProjectPath() {
		URL url = Xmlparser.class.getProtectionDomain().getCodeSource().getLocation();
		String filePath = null;
		try {
			filePath = URLDecoder.decode(url.getPath(), "utf-8");// 转化为utf-8编码
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (filePath.endsWith(".jar")) {// 可执行jar包运行的结果里包含".jar"
			// 截取路径中的jar包名
			
			filePath = filePath.substring(0, filePath.lastIndexOf("/") + 1);
		}

		File file = new File(filePath);
		
		filePath = file.getAbsolutePath();//得到windows式的路径前面
		return filePath;
	}

//-------------------------------- 解析 xml文件到数据库 -----------------------/
	// 获得解析器
	public static XMLStreamReader getStreamReader(String filename) {
		String xmlFile = exePath + "\\resource\\full_data\\" + filename;
		XMLInputFactory factory = XMLInputFactory.newFactory();
		try {
			XMLStreamReader reader = factory
					.createXMLStreamReader(new FileReader(xmlFile));
			return reader;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (XMLStreamException e) {
			e.printStackTrace();
		}
		return null;
	}

	// 解析单个xml文件
	private void xmlParser(String filename) {
		reader = Xmlparser.getStreamReader(filename);

		int id = 0;
		int sameid = 0;
		int nameExist = 0;
		String tag = "";
		String mark = "";
		String paper = "";
		String person = "";

		// 遍历XML文档
		try {
			int event;
			for (event = reader.next(); event != XMLStreamReader.END_DOCUMENT; event = reader
					.next()) {
				// 如果是元素的开始
				if (event == XMLStreamConstants.START_ELEMENT) {

					tag = reader.getLocalName();

					if ("identifier".equalsIgnoreCase(tag)
							&& reader.getNamespaceURI() == null) {
						id = Integer.parseInt(reader.getElementText().trim().split(":")[2]);
						System.out.println("id:" + id);
					} else if ("title".equalsIgnoreCase(tag)) {
						paper += "type:paper@@title:"
								+ reader.getElementText().trim();
						// System.out.println("title:" +
						// reader.getElementText().trim());
					} else if ("description".equalsIgnoreCase(tag)) {
						 paper += "@@description:" +	reader.getElementText().trim();
					} else if ("date".equalsIgnoreCase(tag)) {
						// System.out.println("date:" +
						// reader.getElementText().trim());
						paper += "@@date:" + reader.getElementText().trim();
					} else if ("source".equalsIgnoreCase(tag)) {
						paper += "@@source:" + reader.getElementText().trim();
					} else if ("uri".equalsIgnoreCase(tag)) {// 处理引用关系
						String pid = reader.getElementText().trim().split(":")[2];
						String value=null;
						if((value=cdb.readEdge(id + " " + pid)) == null){//不存在cite 关系了
							if((value=cdb.readEdge(pid + " " + id)) == null){
								cdb.insertEdge( id + " " + pid, "cite ");// 把引用关系写入数据库
							}else{
								cdb.insertEdge( pid + " " + id, value + " cited");//这两个节点相互引用！故只需要加入 cited关系即可
							}
						}
						
//						 System.out.println("relarion:" + id+" "+ reader.getElementText().trim().split(":")[2]);
					} else if ("author".equalsIgnoreCase(tag)) {
						// System.out.println("author:"+reader.getAttributeValue(null,
						// "name"));
						person += "type:person@@name:"
								+ reader.getAttributeValue(null, "name").trim();
					} else if ("address".equalsIgnoreCase(tag)) {
						person += "@@address:" + reader.getElementText().trim();
						if (authors.containsKey(person)) {
							nameExist = 1;							
//							System.out.println("same name:" +person);
						} else {
							authors.put(person, authorId);
						}
					} else if (nameExist != 1
							&& "affiliation".equalsIgnoreCase(tag)) {
						person += "@@affiliation:"
								+ reader.getElementText().trim();
						// System.out.println("affiliation:" +
						// reader.getElementText().trim());
					}
				} else if (event == XMLStreamConstants.END_ELEMENT) {
					mark = reader.getLocalName();
					if ("author".equalsIgnoreCase(mark)) {// 以完成person数据的构造
						if(nameExist != 1){
//							System.out.println("vertex(person):" + person);
							 cdb.insertVertex(authorId, person);//插入vertex数据库
							 cdb.insertEdge(authorId+" "+id, "write ");//插入edge表
							 authorId++;
						}else{
							sameid = authors.get(person);
							cdb.insertEdge(sameid+" "+id, "write ");//insert this person --> paper
						}
						person = "";
						nameExist = 0;
					} else if ("oai_citeseer".equalsIgnoreCase(mark)) {
//						 System.out.println("vertex(paper):" + paper);
						 cdb.insertVertex(id, paper);
						paper = "";
					}
				}
			}
			reader.close();
		} catch (XMLStreamException e) {
			 e.printStackTrace();
			try {
				logfw.append("filename:" + filename
						+ "\n======================\n" + e.toString()
						+ "\n============================\n");
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}
	}

	// 解析单个xml文件 或者 文件夹下的xml文档
	public void parseXML(String path) {
		cdb = Xmlparser.getDb();// 取得数据库操作的句柄，并打开数据库
		try {
			logfw = new FileWriter(log);
			File f = new File(path);
			if (f.isDirectory()) {
				String[] filelist = f.list();
				for (int i = 0; i < filelist.length; i++) {
					xmlParser(filelist[i]);
				}
			} else {// 如果不是目录，则直接处理该文件
				xmlParser(path);
			}

			logfw.close();//将log写入文件

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		cdb.closeDb();
	}

//---------------------------------- 对原始数据做预处理 --------------------------/

	//主要将xml文档中一些非法的unicode编码去掉(这些编码会破坏xml的指令结构),主要依靠atlassian-xml-cleaner-0.1.jar这个jar包
	public void removeValidUnicode() {
		for (int i = 1; i <= NUM_OF_XML_SPLITS; i++) {
			try {
//				System.out.println("cmd /c java -jar F:\\sang\\code\\ParseCiteseer\\jar\\atlassian-xml-cleaner-0.1.jar  F:\\sang\\oai_citeseer\\oai_citeseer\\"
//								+ "oai_citeseer" + i + ".dump > oai_"+i+"_new");
				Runtime.getRuntime()
						.exec("cmd /c java -jar F:\\sang\\code\\ParseCiteseer\\jar\\atlassian-xml-cleaner-0.1.jar  F:\\sang\\oai_citeseer\\oai_citeseer\\"
								+ "oai_citeseer" + i + ".dump > oai_"+i+"_new");

			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public void addRootElement() {
		BufferedReader br = null;
		String line = "";
		String path = "";
		FileWriter fw = null;
		for (int i = 1; i <= NUM_OF_XML_SPLITS; i++) {
			path = exePath + "\\resource\\full_data\\oai_" + i + "_new";
			try {
				br = new BufferedReader(new FileReader(new File(path)));
				fw = new FileWriter(path + "_r");
				fw.write("<root>\n");
				while (br.ready()) {
					line = br.readLine();
					if (line.trim().startsWith("<oai_citeseer:author name")) {						
						String[] splits = line.split("\"");
						if (splits.length == 4) {
//							System.out.println("before::::"+line);
							line = splits[0] + "\"" + splits[1] + splits[2]
									+ "\"" + splits[3];
//							System.out.println("after::::"+line+"\n");
						}
					}
					fw.write(line + "\n");
					
				}
				fw.write("</root>\n");
				fw.close();
				br.close();
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

//--------------------------------- 测试 打印 数据 ---------------------------------/
	public void print() {
		CiteseerDb cdb = Xmlparser.getDb();
		System.out.println(cdb.readVertex(2));
		System.out.println(cdb.readEdge("2 97473"));
		cdb.closeDb();
	}

//---------------------------------- 导出数据 --------------------------------------/
	public void exportFromDb(){
		String path = exePath + "resource\\vertexAndEdge\\";
		FileWriter vfw = null;//节点
		FileWriter efw = null;//边
		CiteseerDb cdb = Xmlparser.getDb();
		try{
			vfw = new FileWriter(path +"vertex_simple.txt");
			efw = new FileWriter(path + "edge_simple.txt");
			
//			cdb.printDB(vfw,efw);
			cdb.printSimpleDB(vfw, efw);
			
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
			try {
				vfw.close();
				efw.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		cdb.closeDb();		
	}
	
//---------------------------------- Main 函数 部分 ------------------------------/
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Xmlparser xp = new Xmlparser();
		
		//对原数据进行预处理
//		xp.removeValidUnicode();
//		xp.addRootElement();// add root tag
		

		for (int i = 1; i <= NUM_OF_XML_SPLITS; i++) {
			 xp.parseXML("oai_"+i+"_new_r");
		}
		
		xp.exportFromDb();
	}

}
